home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fs / fsNameOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-07  |  24.5 KB  |  831 lines

  1. /* 
  2.  * fsNameOps.c --
  3.  *
  4.  *    This has procedures for the operations done on file names
  5.  *    like open and remove.  The name lookups are done via
  6.  *    Fsprefix_LookupOperation which uses the prefix table to choose the server.
  7.  *
  8.  * Copyright (C) 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /sprite/src/kernel/fs/RCS/fsNameOps.c,v 9.3 90/12/06 21:57:16 jhh Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <fs.h>
  26. #include <fsio.h>
  27. #include <fsutil.h>
  28. #include <fsNameOps.h>
  29. #include <fsutilTrace.h>
  30. #include <fsStat.h>
  31. #include <fsprefix.h>
  32. #include <proc.h>
  33. #include <rpc.h>
  34. #include <dbg.h>
  35. #include <string.h>
  36. #include <stdio.h>
  37.  
  38.  
  39. /*
  40.  *----------------------------------------------------------------------
  41.  *
  42.  * Fs_Open --
  43.  *
  44.  *      This routine sets up a Fs_Stream object for the named file.  The
  45.  *      parameters specify the manner in which the stream will be used and
  46.  *      a set of permission bits in case a file needs to be created for
  47.  *      the stream.
  48.  *
  49.  * Results:
  50.  *      An error code, and a pointer to a Fs_Stream object for the file.
  51.  *      This is used in further operations on the file and is released
  52.  *      with Fs_Close
  53.  *
  54.  * Side effects:
  55.  *    The stream is opened.
  56.  *
  57.  *----------------------------------------------------------------------
  58.  */
  59. ReturnStatus
  60. Fs_Open(name, useFlags, type, permissions, streamPtrPtr)
  61.     char     *name;        /* The name of the file to open */
  62.     register int useFlags;    /* Indicates read/write etc. the valid bits 
  63.                  * to include are defined in fs.h */
  64.     int     type;        /* If FS_FILE then any type of file can be 
  65.                  * opened, except if useFlags includes 
  66.                  * FS_CREATE then a regular file will be 
  67.                  * created.  Otherwise only the specified 
  68.                  * type can be opened (or created). */
  69.     int     permissions;    /* A mask indicating the permission bits to 
  70.                  * turn on if the file gets created */
  71.     Fs_Stream     **streamPtrPtr;    /* Contents set to point to a valid stream
  72.                   * or NIL if there was an error. */
  73. {
  74.     register Fs_Stream     *streamPtr;    /* Local copy of stream pointer */
  75.     ReturnStatus     status;        /* Return error code from RPC */
  76. #ifdef SOSP91
  77.     Fs_OpenArgsSOSP         openArgs;    /* Packaged up parameters */
  78. #else
  79.     Fs_OpenArgs         openArgs;    /* Packaged up parameters */
  80. #endif
  81.     Fs_OpenResults     openResults;    /* Packaged up results */
  82.     Proc_ControlBlock    *procPtr;    /* Used to get process IDs */
  83.     Fs_NameInfo        *nameInfoPtr;    /* Used to track name and prefix */
  84.  
  85.     *streamPtrPtr = (Fs_Stream *)NIL;
  86.  
  87.     if ((useFlags & FS_EXECUTE) && (useFlags & (FS_WRITE | FS_CREATE))) {
  88.     return(FS_INVALID_ARG);
  89.     }
  90.     
  91.     /*
  92.      * Override the type if user flags indicate special files.
  93.      */
  94.     if (useFlags & FS_NAMED_PIPE_OPEN) {
  95.     printf( "Named pipes (%s) not implemented\n", name);
  96.     return(FS_INVALID_ARG);
  97.     } else if (useFlags & FS_PDEV_MASTER) {
  98.     type = FS_PSEUDO_DEV;
  99.     } else if (useFlags & FS_PFS_MASTER) {
  100.     type = FS_REMOTE_LINK;
  101.     useFlags &= ~FS_FOLLOW;
  102.     }
  103.     /*
  104.      * Make sure we check for write permission before truncating.
  105.      */
  106.     if (useFlags & FS_TRUNC) {
  107.     useFlags |= FS_WRITE;
  108.     }
  109.  
  110.     /*
  111.      * Set up arguments to the Domain specific open routine.  The domain
  112.      * open routine returns streamData used to set up the I/O handle
  113.      * by the client open routine called below.  The stream's nameInfo is
  114.      * set up as a side effect of going through Fsprefix_LookupOperation.
  115.      */
  116.     procPtr = Proc_GetEffectiveProc();
  117.     if (type != FS_SYMBOLIC_LINK && type != FS_REMOTE_LINK) {
  118.     openArgs.permissions    = permissions & procPtr->fsPtr->filePermissions;
  119.     } else {
  120.     openArgs.permissions    = permissions;
  121.     }
  122.     openArgs.useFlags        = useFlags;
  123.     openArgs.type        = type;
  124.     openArgs.clientID        = rpc_SpriteID;
  125.     if (procPtr->genFlags & PROC_FOREIGN) {
  126.     openArgs.migClientID    = procPtr->peerHostID;
  127.     } else {
  128.     openArgs.migClientID    = rpc_SpriteID;
  129.     }
  130.     openResults.streamData    = (ClientData) NIL;
  131.     Fs_SetIDs(procPtr, &openArgs.id);
  132. #ifdef SOSP91
  133.     openArgs.realID = procPtr->userID;
  134.     openResults.dataSize = sizeof(Fs_OpenArgsSOSP);
  135. #endif
  136.     nameInfoPtr = mnew(Fs_NameInfo);
  137.  
  138.     FSUTIL_TRACE_NAME(FSUTIL_TRACE_OPEN_START, name);
  139.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_OPEN, useFlags & FS_FOLLOW,
  140.             (Address)&openArgs, (Address)&openResults, nameInfoPtr);
  141.     FSUTIL_TRACE_NAME(FSUTIL_TRACE_OPEN_DONE, name);
  142.     if (status == SUCCESS) {
  143.     /*
  144.      * Install the stream and then call the client open procedure
  145.      * to complete the setup of the stream's I/O handle
  146.      */
  147.     streamPtr = Fsio_StreamAddClient(&openResults.streamID, rpc_SpriteID,
  148.                  (Fs_HandleHeader *)NIL,
  149.                  useFlags, name, (Boolean *)NIL, (Boolean *)NIL);
  150.     streamPtr->nameInfoPtr = nameInfoPtr;
  151.     Fsutil_HandleUnlock(streamPtr);
  152.     status = (*fsio_StreamOpTable[openResults.ioFileID.type].ioOpen)
  153.             (&openResults.ioFileID, &streamPtr->flags, rpc_SpriteID,
  154.              openResults.streamData, name, &streamPtr->ioHandlePtr);
  155.     if (status == SUCCESS) {
  156.         if (streamPtr->flags & FS_TRUNC) {
  157.         (void)Fs_TruncStream(streamPtr, 0);
  158.         }
  159. #ifdef SOSP91
  160.         streamPtr->hdr.flags &= ~FSUTIL_RW_FLAGS;
  161. #endif
  162.         *streamPtrPtr = streamPtr;
  163.         switch (useFlags & (FS_READ | FS_WRITE)) {
  164.         case FS_READ:
  165.             fs_Stats.cltName.numReadOpens ++;
  166.             break;
  167.         case FS_WRITE:
  168.             fs_Stats.cltName.numWriteOpens ++;
  169.             break;
  170.         case (FS_READ | FS_WRITE):
  171.             fs_Stats.cltName.numReadWriteOpens ++;
  172.             break;
  173.         default:
  174.             break;
  175.         }
  176.     } else {
  177.         /*
  178.          * Client open procedure failed.  Clean up the stream.
  179.          */
  180.         Fsutil_HandleLock(streamPtr);
  181.         (void)Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID);
  182.         Fsio_StreamDestroy(streamPtr);
  183.     }
  184.     } else {
  185.     free((Address)nameInfoPtr);
  186.     }
  187.     return(status);
  188. }
  189.  
  190. /*
  191.  *----------------------------------------------------------------------
  192.  *
  193.  * Fs_SetIDs --
  194.  *
  195.  *    Get user ID and group IDs from the proc table.  The FsUserID
  196.  *    struct includes storage for the list of groups.  Alternatively,
  197.  *    it could contain a pointer to the groups in the proc table.
  198.  *
  199.  *    TODO: Byte the bullet and figure out a nice way to pass a
  200.  *    variable length list of groups around.  Then this procedure
  201.  *    would not be needed, and the Fs_ProcessState could be
  202.  *    referenced directly.  The ugliest place to do all this is
  203.  *    in the RPC stubs.
  204.  *
  205.  * Results:
  206.  *    None.
  207.  *
  208.  * Side effects:
  209.  *    Instantiate *idPtr to hold the user and group IDs of the current proc.
  210.  *
  211.  *----------------------------------------------------------------------
  212.  */
  213. void
  214. Fs_SetIDs(procPtr, idPtr)
  215.     Proc_ControlBlock         *procPtr;
  216.     Fs_UserIDs            *idPtr;
  217. {
  218.     register    Fs_ProcessState *fsPtr;
  219.     register    int    *procGroupIDs;
  220.     register    int    *groupPtr;
  221.     register     int     i;
  222.  
  223.     if (procPtr == (Proc_ControlBlock *)NIL) {
  224.     procPtr = Proc_GetEffectiveProc();
  225.     }
  226.     idPtr->user = procPtr->effectiveUserID;
  227.  
  228.     fsPtr = procPtr->fsPtr;
  229.     if (fsPtr == (Fs_ProcessState *)NIL) {
  230.     /*
  231.      * Exiting processes remove swap files after clearing fs state.
  232.      */
  233.     idPtr->numGroupIDs = 0;
  234.     procGroupIDs = (int *)NIL;
  235.     } else {
  236.     idPtr->numGroupIDs = fsPtr->numGroupIDs;
  237.     procGroupIDs = fsPtr->groupIDs;
  238.     }
  239.     for (i = 0, groupPtr = idPtr->group; i < FS_NUM_GROUPS;  i++, groupPtr++) {
  240.     /*
  241.      * The file system state record supports a variable length array of
  242.      * group IDs but here we truncate it...
  243.      */
  244.     if (i < idPtr->numGroupIDs) {
  245.         *groupPtr = *procGroupIDs;
  246.         procGroupIDs++;
  247.     } else {
  248.         *groupPtr = -1;
  249.     }
  250.     }
  251. }
  252.  
  253. /*
  254.  *----------------------------------------------------------------------
  255.  *
  256.  * Fs_Remove --
  257.  *
  258.  *    Remove the named file.  Because each entry in a directory is only
  259.  *    one of many posible references, the disk space for the file may or
  260.  *    may not be freed after this call.   Only when the last link to
  261.  *    the file is removed is the disk space freed up.  This does not
  262.  *    follow links so that links are removed instead of the file
  263.  *    they reference.
  264.  *
  265.  * Results:
  266.  *    An error code.
  267.  *
  268.  * Side effects:
  269.  *    The file is removed
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273. ReturnStatus
  274. Fs_Remove(name)
  275.     char *name;        /* The name of the file to remove */
  276. {
  277.     ReturnStatus status;
  278.     Fs_LookupArgs lookupArgs;
  279.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  280.  
  281.     lookupArgs.useFlags = FS_DELETE;
  282.     Fs_SetIDs(procPtr, &lookupArgs.id);
  283.     lookupArgs.clientID = rpc_SpriteID;
  284.     if (procPtr->genFlags & PROC_FOREIGN) {
  285.     lookupArgs.migClientID    = procPtr->peerHostID;
  286.     } else {
  287.     lookupArgs.migClientID    = rpc_SpriteID;
  288.     }
  289.     fs_Stats.cltName.removes++;
  290.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE, 0,
  291.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  292.     return(status);
  293. }
  294.  
  295. /*
  296.  *----------------------------------------------------------------------
  297.  *
  298.  * Fs_RemoveDir --
  299.  *
  300.  *    Remove the named directory.  It must be empty, that is it should
  301.  *    only contain entries for itself (.) and its parent (..).
  302.  *
  303.  * Results:
  304.  *    An error code.
  305.  *
  306.  * Side effects:
  307.  *    The directory is removed if possible
  308.  *
  309.  *----------------------------------------------------------------------
  310.  */
  311. ReturnStatus
  312. Fs_RemoveDir(name)
  313.     char *name;        /* The name of the directory to remove */
  314. {
  315.     ReturnStatus status;
  316.     Fs_LookupArgs lookupArgs;
  317.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  318.  
  319.     lookupArgs.useFlags = FS_DELETE;
  320.     Fs_SetIDs(procPtr, &lookupArgs.id);
  321.     lookupArgs.clientID = rpc_SpriteID;
  322.     if (procPtr->genFlags & PROC_FOREIGN) {
  323.     lookupArgs.migClientID    = procPtr->peerHostID;
  324.     } else {
  325.     lookupArgs.migClientID    = rpc_SpriteID;
  326.     }
  327.     fs_Stats.cltName.removeDirs++;
  328.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE_DIR, 0,
  329.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  330.     return(status);
  331. }
  332.  
  333. /*
  334.  *----------------------------------------------------------------------
  335.  *
  336.  * Fs_MakeDevice --
  337.  *
  338.  *    Make the named device file.  This is the procedure which
  339.  *    does the actual work for the Fs_MakeDevice system call.
  340.  *
  341.  * Results:
  342.  *    An error code.
  343.  *
  344.  * Side effects:
  345.  *    The device file is made
  346.  *
  347.  *----------------------------------------------------------------------
  348.  */
  349. ReturnStatus
  350. Fs_MakeDevice(name, devicePtr, permissions)
  351.     char *name;            /* The name of the directory to make */
  352.     Fs_Device *devicePtr;    /* Specifies device info */
  353.     int permissions;        /* The permissions for the new directory */
  354. {
  355.     ReturnStatus status;    /* Return error code */
  356.     Fs_MakeDeviceArgs makeDevArgs;/* Packaged up parameters */
  357.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  358.  
  359.     if (((devicePtr->serverID != FS_LOCALHOST_ID) &&
  360.     (devicePtr->serverID <= 0)) ||
  361.     (devicePtr->type < 0) ||
  362.     (devicePtr->unit < 0)) {
  363.     return(FS_INVALID_ARG);
  364.     }
  365.     procPtr = Proc_GetEffectiveProc();
  366.     makeDevArgs.device         = *devicePtr;
  367.     makeDevArgs.open.permissions= permissions & procPtr->fsPtr->filePermissions;
  368.     Fs_SetIDs(procPtr, &makeDevArgs.open.id);
  369.     makeDevArgs.open.clientID    = rpc_SpriteID;
  370.     if (procPtr->genFlags & PROC_FOREIGN) {
  371.     makeDevArgs.open.migClientID    = procPtr->peerHostID;
  372.     } else {
  373.     makeDevArgs.open.migClientID    = rpc_SpriteID;
  374.     }
  375.  
  376.     fs_Stats.cltName.makeDevices++;
  377.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DEVICE, 0,
  378.              (Address)&makeDevArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  379.     return(status);
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * Fs_MakeDir --
  386.  *
  387.  *    Make the named directory.  This is the procedure which
  388.  *    does the actual work for the Fs_MakeDir system call.
  389.  *
  390.  * Results:
  391.  *    An error code.
  392.  *
  393.  * Side effects:
  394.  *    The directory is made
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398. ReturnStatus
  399. Fs_MakeDir(name, permissions)
  400.     char *name;        /* The name of the directory to make */
  401.     int permissions;    /* The permissions for the new directory */
  402. {
  403.     ReturnStatus status;    /* Return error code from RPC */
  404.     Fs_OpenArgs openArgs;    /* Packaged up parameters */
  405.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  406.  
  407.     procPtr = Proc_GetEffectiveProc();
  408.     openArgs.useFlags = FS_CREATE | FS_EXCLUSIVE | FS_FOLLOW ;
  409.     openArgs.permissions = permissions & procPtr->fsPtr->filePermissions;
  410.     openArgs.type = FS_DIRECTORY;
  411.     Fs_SetIDs(procPtr, &openArgs.id);
  412.     openArgs.clientID = rpc_SpriteID;
  413.     if (procPtr->genFlags & PROC_FOREIGN) {
  414.     openArgs.migClientID    = procPtr->peerHostID;
  415.     } else {
  416.     openArgs.migClientID    = rpc_SpriteID;
  417.     }
  418.     fs_Stats.cltName.makeDirs++;
  419.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DIR, FS_FOLLOW,
  420.             (Address)&openArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  421.     return(status);
  422. }
  423.  
  424. /*
  425.  *----------------------------------------------------------------------
  426.  *
  427.  * Fs_ChangeDir --
  428.  *
  429.  *    Change the process's current directory.  This opens the
  430.  *    new current directory, and if that's successful the
  431.  *    old one is closed.
  432.  *
  433.  * Results:
  434.  *    An error code.
  435.  *
  436.  * Side effects:
  437.  *    Change the current directory.
  438.  *
  439.  *----------------------------------------------------------------------
  440.  */
  441. ReturnStatus
  442. Fs_ChangeDir(pathName)
  443.     char *pathName;
  444. {
  445.     register    Fs_ProcessState *fsPtr;
  446.     Fs_Stream        *newCwdPtr;    /* A stream is used because it has
  447.                      * a reference count and can be
  448.                      * closed with existing routines. */
  449.     ReturnStatus    status;
  450.  
  451.     fsPtr = (Proc_GetEffectiveProc())->fsPtr;
  452.  
  453.     /*
  454.      * FS_EXECUTE permission needed to change to a directory.
  455.      */
  456.     newCwdPtr = (Fs_Stream *)NIL;
  457.     fs_Stats.cltName.chdirs++;
  458.     status = Fs_Open(pathName, FS_EXECUTE | FS_FOLLOW, FS_DIRECTORY, 0,
  459.                   &newCwdPtr);
  460.     if (status) {
  461.     return(status);
  462.     }
  463.     (void)Fs_Close(fsPtr->cwdPtr);
  464.     fsPtr->cwdPtr = newCwdPtr;
  465.     return(SUCCESS);
  466. }
  467.  
  468. /*
  469.  *----------------------------------------------------------------------
  470.  *
  471.  * Fs_Trunc --
  472.  *
  473.  *    Truncate a file to a given length given its pathname.
  474.  *
  475.  * Results:
  476.  *    An error code
  477.  *
  478.  * Side effects:
  479.  *    The files length gets set and any data beyond that is deleted.
  480.  *
  481.  *----------------------------------------------------------------------
  482.  */
  483. ReturnStatus
  484. Fs_Trunc(pathName, length)
  485.     char *pathName;
  486.     int length;
  487. {
  488.     Fs_Stream *streamPtr;
  489.     ReturnStatus status;
  490.  
  491.     streamPtr = (Fs_Stream *)NIL;
  492.     status = Fs_Open(pathName, FS_WRITE | FS_FOLLOW, FS_FILE, 0, &streamPtr);
  493.     if (status != SUCCESS) {
  494.     return(status);
  495.     }
  496.     status = Fs_TruncStream(streamPtr, length);
  497.     (void)Fs_Close(streamPtr);
  498.     return(status);
  499. }
  500.  
  501. /*
  502.  *----------------------------------------------------------------------
  503.  *
  504.  * Fs_TruncStream --
  505.  *
  506.  *    Truncate a file to a given length given an open stream.
  507.  *    This is a thin layer on top of Fs_IOControl that is called
  508.  *    from Fs_Trunc and from Fs_Open.
  509.  *
  510.  * Results:
  511.  *    An error code
  512.  *
  513.  * Side effects:
  514.  *    The files length gets set and any data beyond that is deleted.
  515.  *
  516.  *----------------------------------------------------------------------
  517.  */
  518. ReturnStatus
  519. Fs_TruncStream(streamPtr, length)
  520.     Fs_Stream *streamPtr;
  521.     int length;
  522. {
  523.     ReturnStatus status;
  524.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  525.     Fs_IOCParam ioctl;
  526.     Fs_IOReply reply;
  527.  
  528.     if (length < 0) {
  529.     return(GEN_INVALID_ARG);
  530.     }
  531.     ioctl.command = IOC_TRUNCATE;
  532.     ioctl.inBuffer = (Address)&length;
  533.     ioctl.inBufSize = sizeof(int);
  534.     ioctl.outBuffer = (Address) NIL;
  535.     ioctl.outBufSize = 0;
  536.     ioctl.format = mach_Format;
  537.     ioctl.procID = procPtr->processID;
  538.     ioctl.familyID = procPtr->familyID;
  539.     ioctl.uid = procPtr->effectiveUserID;
  540.     ioctl.flags = 0;
  541.  
  542.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  543.     return(status);
  544. }
  545.  
  546. /*
  547.  *----------------------------------------------------------------------
  548.  *
  549.  * Fs_GetAttributes --
  550.  *
  551.  *    Get the attributes of a file given its name.  First the name server
  552.  *    is contacted to get the initial version of the attributes.  Then
  553.  *    the I/O server is contacted to update attributes like the
  554.  *    access and modify times.
  555.  *
  556.  * Results:
  557.  *    An error code and the attributes.
  558.  *
  559.  * Side effects:
  560.  *    None here.
  561.  *
  562.  *----------------------------------------------------------------------
  563.  */
  564.  
  565. ReturnStatus
  566. Fs_GetAttributes(pathName, fileOrLink, attrPtr)
  567.     char *pathName;
  568.     int fileOrLink;        /* FS_ATTRIB_FILE or FS_ATTRIB_LINK */
  569.     Fs_Attributes *attrPtr;
  570. {
  571.     ReturnStatus status;
  572.     Fs_OpenArgs openArgs;
  573.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  574.     Fs_GetAttrResults getAttrResults;    /* References attrPtr and ioFileID */
  575.     Fs_FileID ioFileID;            /* Returned from name server, indicates
  576.                      * who the I/O server is. */
  577.  
  578.     openArgs.useFlags = (fileOrLink == FS_ATTRIB_LINK) ? 0 : FS_FOLLOW;
  579.     openArgs.permissions = 0;
  580.     openArgs.type = FS_FILE;
  581.     openArgs.clientID = rpc_SpriteID;
  582.     Fs_SetIDs(procPtr, &openArgs.id);
  583.     if (procPtr->genFlags & PROC_FOREIGN) {
  584.     openArgs.migClientID    = procPtr->peerHostID;
  585.     } else {
  586.     openArgs.migClientID    = rpc_SpriteID;
  587.     }
  588.  
  589.     getAttrResults.attrPtr = attrPtr;
  590.     getAttrResults.fileIDPtr = &ioFileID;
  591.  
  592.     /*
  593.      * Get an initial version of the attributes from the name server.
  594.      */
  595.     fs_Stats.cltName.getAttrs++;
  596.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_GET_ATTR, openArgs.useFlags,
  597.          (Address)&openArgs, (Address)&getAttrResults,
  598.          (Fs_NameInfo *)NIL);
  599.     if ((status == SUCCESS) &&
  600.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  601.     /*
  602.      * Update those with attributes cached at the I/O server.
  603.      * This is suppressed by setting the ioFileID.type < 0
  604.      */
  605.     fs_Stats.cltName.getIOAttrs++;
  606.     status = (*fsio_StreamOpTable[ioFileID.type].getIOAttr)
  607.             (&ioFileID, rpc_SpriteID, attrPtr);
  608. #ifdef lint
  609.     status = Fsrmt_GetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  610.     status = FsrmtFileGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  611.     status = Fsio_DeviceGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  612.     status = Fsio_PipeGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  613. #endif lint
  614.     }
  615.     return(status);
  616. }
  617.  
  618. /*
  619.  *----------------------------------------------------------------------
  620.  *
  621.  * Fs_SetAttributes --
  622.  *
  623.  *    Set some attributes of a file given its name.  The input contains
  624.  *    the complete set of attributes for the file but not all of these
  625.  *    are affected by this call.  Ie.  the user can't change everything.
  626.  *    The name server is contacted first to set attributes file descriptor,
  627.  *    then the I/O server is contacted to update cached attributes.
  628.  *
  629.  * Results:
  630.  *    An error code
  631.  *
  632.  * Side effects:
  633.  *    See FsLocalSetAttrID for which attributes get updated at the
  634.  *    file server.
  635.  *
  636.  *     If the operation is successful, the count of setAttrs is incremented.
  637.  *
  638.  *----------------------------------------------------------------------
  639.  */
  640. ReturnStatus
  641. Fs_SetAttributes(pathName, fileOrLink, attrPtr, flags)
  642.     char *pathName;
  643.     int fileOrLink;
  644.     Fs_Attributes *attrPtr;
  645.     int flags;
  646. {
  647.     register ReturnStatus status;
  648.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  649.     Fs_SetAttrArgs setAttrArgs;        /* Bundled openArgs and attributes */
  650.     Fs_OpenArgs *openArgsPtr;        /* Pointer into setAttrArgs */
  651.     Fs_FileID ioFileID;            /* Used to get to I/O server */
  652.  
  653.     openArgsPtr = &setAttrArgs.openArgs;
  654.     openArgsPtr->useFlags = FS_OWNERSHIP;
  655.     if (fileOrLink == FS_ATTRIB_FILE) {
  656.     openArgsPtr->useFlags |= FS_FOLLOW;
  657.     }
  658.     openArgsPtr->permissions = 0;
  659.     openArgsPtr->type = FS_FILE;
  660.     openArgsPtr->clientID = rpc_SpriteID;
  661.     Fs_SetIDs(procPtr, &openArgsPtr->id);
  662.     if (procPtr->genFlags & PROC_FOREIGN) {
  663.     openArgsPtr->migClientID = procPtr->peerHostID;
  664.     } else {
  665.     openArgsPtr->migClientID = rpc_SpriteID;
  666.     }
  667.  
  668.     /*
  669.      * This copy is done here to avoid doing it in the client RPC stub.
  670.      */
  671.     setAttrArgs.attr = *attrPtr;
  672.     setAttrArgs.flags = flags;
  673.  
  674.     /*
  675.      * Set the attributes at the name server.  We get in return a fileID
  676.      * for the actual device which specifies a serverID.
  677.      */
  678.     fs_Stats.cltName.setAttrs++;
  679.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_SET_ATTR, 0,
  680.              (Address)&setAttrArgs, (Address)&ioFileID,
  681.              (Fs_NameInfo *)NIL);
  682.     if ((status == SUCCESS) &&
  683.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  684.     /*
  685.      * Set the attributes at the I/O server.
  686.      */
  687.     fs_Stats.cltName.setIOAttrs++;
  688.     status = (*fsio_StreamOpTable[ioFileID.type].setIOAttr)
  689.             (&ioFileID, attrPtr, flags);
  690. #ifdef lint
  691.     status = Fsrmt_SetIOAttr(&ioFileID, attrPtr, flags);
  692.     status = FsrmtFileSetIOAttr(&ioFileID, attrPtr, flags);
  693.     status = Fsio_DeviceSetIOAttr(&ioFileID, attrPtr, flags);
  694.     status = Fsio_PipeSetIOAttr(&ioFileID, attrPtr, flags);
  695. #endif lint
  696.     }
  697.     return(status);
  698. }
  699.  
  700. /*
  701.  *----------------------------------------------------------------------
  702.  *
  703.  * Fs_HardLink --
  704.  *
  705.  *      Make two pathnames refer to the same file.  The pathnames are
  706.  *      restricted to be in the same domain, ie. stored on the same
  707.  *      disk pack, so the file server can make the link.
  708.  *
  709.  * Results:
  710.  *      SUCCESS if the link was made.  FS_CANT_LINK if the pathnames
  711.  *      are not in the same domain.
  712.  *
  713.  * Side effects:
  714.  *      Cause the two pathnames to refer to the same file.
  715.  *
  716.  *----------------------------------------------------------------------
  717.  */
  718. ReturnStatus
  719. Fs_HardLink(pathName, linkName)
  720.     char *pathName;    /* Name of the existing file */
  721.     char *linkName;    /* Name of the file to create which is a link to
  722.              * the existing file */
  723. {
  724.     ReturnStatus status;
  725.     Fs_LookupArgs lookupArgs;
  726.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  727.  
  728.     lookupArgs.useFlags = FS_LINK;
  729.     Fs_SetIDs(procPtr, &lookupArgs.id);
  730.     lookupArgs.clientID = rpc_SpriteID;
  731.     if (procPtr->genFlags & PROC_FOREIGN) {
  732.     lookupArgs.migClientID    = procPtr->peerHostID;
  733.     } else {
  734.     lookupArgs.migClientID    = rpc_SpriteID;
  735.     }
  736.     fs_Stats.cltName.hardLinks++;
  737.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_HARD_LINK, pathName, linkName,
  738.                              &lookupArgs);
  739.     return(status);
  740. }
  741.  
  742. /*
  743.  *----------------------------------------------------------------------
  744.  *
  745.  * Fs_Rename --
  746.  *
  747.  *    Change the name of a file.  This is complicated because the files
  748.  *    can only be in the same domain.  This is not directly evident.
  749.  *
  750.  * Results:
  751.  *      SUCCESS if the name was changed.
  752.  *
  753.  * Side effects:
  754.  *    Change the name of a file.
  755.  *
  756.  *----------------------------------------------------------------------
  757.  */
  758. ReturnStatus
  759. Fs_Rename(pathName, newName)
  760.     char *pathName;    /* Name of the existing file */
  761.     char *newName;    /* The new pathname for the file */
  762. {
  763.     ReturnStatus status;
  764.     Fs_LookupArgs lookupArgs;
  765.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  766.  
  767.     lookupArgs.useFlags = FS_LINK | FS_RENAME;
  768.     Fs_SetIDs(procPtr, &lookupArgs.id);
  769.     lookupArgs.clientID = rpc_SpriteID;
  770.     if (procPtr->genFlags & PROC_FOREIGN) {
  771.     lookupArgs.migClientID    = procPtr->peerHostID;
  772.     } else {
  773.     lookupArgs.migClientID    = rpc_SpriteID;
  774.     }
  775.     fs_Stats.cltName.renames++;
  776.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_RENAME, pathName, newName,
  777.                           &lookupArgs);
  778.     return(status);
  779. }
  780.  
  781. /*
  782.  *----------------------------------------------------------------------
  783.  *
  784.  * Fs_SymLink --
  785.  *
  786.  *    Create a symbolic link file by writing the name of the target
  787.  *    file (including the NULL) into the link file.  This only
  788.  *    succeeds if the link file does not already exist.
  789.  *
  790.  * Results:
  791.  *      SUCCESS if the link was created.
  792.  *
  793.  * Side effects:
  794.  *    Create the file and write the link name into it.
  795.  *
  796.  *----------------------------------------------------------------------
  797.  */
  798. ReturnStatus
  799. Fs_SymLink(targetName, linkName, remoteFlag)
  800.     char *targetName;    /* Name of the file to link to */
  801.     char *linkName;    /* The name of the new link file that's created */
  802.     Boolean remoteFlag;    /* TRUE => link will be a REMOTE_LINK */
  803. {
  804.     ReturnStatus status;
  805.     Fs_Stream *streamPtr;
  806.     int length;
  807.  
  808.     if (remoteFlag) {
  809.     /*
  810.      * Could check for super-user only here.
  811.      */
  812.     if (targetName[0] != '/') {
  813.         /*
  814.          * Remote links must be absolute.  They should also be circular,
  815.          * but that is harder to check.
  816.          */
  817.         return(FS_INVALID_ARG);
  818.     }
  819.     }
  820.     fs_Stats.cltName.symLinks++;
  821.     status = Fs_Open(linkName, FS_CREATE | FS_WRITE | FS_EXCLUSIVE,
  822.                 (remoteFlag ? FS_REMOTE_LINK : FS_SYMBOLIC_LINK),
  823.                 0777, &streamPtr);
  824.     if (status == SUCCESS) {
  825.     length = strlen(targetName) + 1;    /* FIX */
  826.     status = Fs_Write(streamPtr, targetName, 0, &length);
  827.     (void)Fs_Close(streamPtr);
  828.     }
  829.     return(status);
  830. }
  831.